#include "inneral/xthread.h"
#include "inneral/xthread-timer.h"
#include "xthread-spinlock.h"

#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/sysinfo.h>

#define PRINT_SCHED 0

static volatile long xthread_next_id = 0;
static LIST_HEAD(xthread_ready_list_head);
static LIST_HEAD(xthread_global_list_head);
static LIST_HEAD(xthread_zombie_list_head);
static xthread_struct_t xthread_master;
xthread_struct_t *xthread_current = NULL;
volatile int __xthread_init_done = 0;
static volatile int xthread_alarm_installed = 0;
volatile clock_t __xthread_alarm_ticks = 0; /* msecounds */
static xthread_spin_lock_t xthread_ready_list_lock;
static xthread_spin_lock_t xthread_global_list_lock;
static xthread_spin_lock_t xthread_zombie_list_lock;
static xthread_spin_lock_t xthread_sched_lock;   /* lock sched */
static xthread_spin_lock_t xthread_counts_lock;   /* lock counts */
static xthread_t xthread_sys_tid;
static volatile unsigned long xthread_counts = 0;    /* how many thread exist */

static void xthread_disablealarm();
static void xthread_enablealarm();
static int xthread_init();
static void xthread_exit_all();
static void xthread_schedule();

static xthread_t xthread_alloc_tid()
{
    // TODO: alloc tid
    return xthread_next_id++;
}

static int xthread_free_tid(xthread_t thread)
{
    // TODO: free tid
    return 0;
}

static int xthread_make_default_attr(xthread_attr_t *attr)
{
    attr->stacksize = XTHREAD_STACKSIZE_DEL;
    attr->stackaddr = malloc(attr->stacksize);
    if (attr->stackaddr == NULL) {
        return ENOMEM;
    }
    memset(attr->stackaddr, 0, attr->stacksize);
    attr->detachstate = XTHREAD_CREATE_JOINABLE;
    return 0;
}

static void panic(void)
{
    fprintf(stderr, "xthread: panic!\n");
    exit(EXIT_FAILURE);
}

int xthread_attr_init(xthread_attr_t *attr)
{
    if (!attr) {
        return EINVAL;
    }
    attr->stacksize = XTHREAD_STACKSIZE_DEL;
    attr->stackaddr = NULL;
    attr->detachstate = XTHREAD_CREATE_JOINABLE;
    return 0;
}

int xthread_attr_destroy(xthread_attr_t *attr)
{
    if (!attr) {
        return EINVAL;
    }
    if (attr->stackaddr)
        free(attr->stackaddr);
    attr->stackaddr = NULL;
    attr->stacksize = 0;
    attr->detachstate = 0;
    return 0;
}

int xthread_attr_getstacksize(const xthread_attr_t *attr, size_t *stacksize)
{
    if (!attr) {
        return EINVAL;
    }
    if (stacksize)
        *stacksize = attr->stacksize; 
    return 0;
}

int xthread_attr_setstacksize(xthread_attr_t *attr, size_t stacksize)
{
    if (!attr) {
        return EINVAL;
    }
    attr->stacksize = stacksize;
    return 0;
}

int xthread_attr_getstackaddr(const xthread_attr_t *attr, void **stackaddr)
{
    if (!attr) {
        return EINVAL;
    }
    if (stackaddr)
        *stackaddr = attr->stackaddr; 
    return 0;
}

int xthread_attr_setstackaddr(xthread_attr_t *attr, void *stackaddr)
{
    if (!attr) {
        return EINVAL;
    }
    if (attr->stackaddr){
        free(attr->stackaddr);  /* free old stack */
    }
    attr->stackaddr = stackaddr;
    return 0;
}

int xthread_attr_getdetachstate(const xthread_attr_t * attr, int * detachstate)
{
    if (!attr) {
        return EINVAL;
    }
    if (detachstate)
        *detachstate = attr->detachstate;
    return 0;
}

int xthread_attr_setdetachstate(xthread_attr_t * attr, int detachstate)
{
    if (!attr) {
        return EINVAL;
    }
    attr->detachstate = detachstate;
    return 0;
}

static xthread_struct_t *xthread_find_by_tid(xthread_t tid)
{
    xthread_struct_t *target_thread = NULL, *tmp;
    xthread_spin_lock(&xthread_global_list_lock);
    list_for_each_owner(tmp, &xthread_global_list_head, global_list) {
        if (xthread_equal(tmp->tid, tid)) {
            target_thread = tmp;
            break;
        }
    }
    xthread_spin_unlock(&xthread_global_list_lock);
    return target_thread;
}

static void xthread_context_init(xthread_struct_t *thread)
{
    getcontext(&thread->context);
    thread->context.uc_stack.ss_sp = thread->attr.stackaddr;
    thread->context.uc_stack.ss_size =thread->attr.stacksize;
    /* swap to master context after swapcontext */
    if (xthread_current) {
        thread->context.uc_link = &xthread_current->context;    
    } else {
        thread->context.uc_link = &xthread_master.context;
    }
}

void xthread_exit_one(xthread_struct_t *thread, void *retval)
{
    if (!__xthread_init_done)
        return;
    xthread_spin_lock(&thread->lock);
    thread->exit_status = retval;
    xthread_state_t state = XTHREAD_ZOMBIE;
    /* if not in current thread, the READY, BLOCK state need do more care */
    if (thread->state == XTHREAD_READY) {
        XPRINT("xthread: %x exit when on ready list\n", thread->tid);
        /* transform to DEFFERED cancel */
        thread->flags &= ~XTHREAD_FLAG_CANCEL_DISABLE;
        thread->flags &= ~XTHREAD_FLAG_CANCEL_ASYCHRONOUS;
        xthread_spin_unlock(&thread->lock);
        return;
    } else if (thread->state == XTHREAD_BLOCK) {
        XPRINT("xthread: %x exit when sleep\n", thread->tid);
        /* when sleep on timer, must cancel timer */
        xthread_timer_cancel(&thread->sleep_timer);    
    }
    /* parent is joining for me */
    if (thread->flags & XTHREAD_FLAG_JOINEDBY) {
        xthread_struct_t *parent_thread = xthread_find_by_tid(thread->parent_tid);
        if (parent_thread && (parent_thread->flags & XTHREAD_FLAG_JOINING)) {
            xthread_spin_lock(&parent_thread->lock);
            parent_thread->flags &= ~XTHREAD_FLAG_JOINING;
            xthread_spin_unlock(&parent_thread->lock);
        }
    }

    /* need release by system */
    if (thread->flags & XTHREAD_FLAG_DETACHED) { 
        XPRINT("xthread: thread %x exit with detached\n", thread->tid);
        
        /* adopt to sys thread  */
        thread->parent_tid = xthread_sys_tid;
    }
    xthread_spin_unlock(&thread->lock);
    /* add to zombie list */
    xthread_spin_lock(&xthread_zombie_list_lock);
    list_add_tail(&thread->list, &xthread_zombie_list_head);
    xthread_spin_unlock(&xthread_zombie_list_lock);
    if (thread == xthread_current) {       
        xthread_block(state);
        return;
    } else {
        thread->state = state;
    }
}

void xthread_exit(void *retval)
{
    if (!__xthread_init_done)
        return;
    xthread_exit_one(xthread_current, retval);
}

void xthread_block(xthread_state_t state)
{
    assert(state == XTHREAD_BLOCK ||
            state == XTHREAD_ZOMBIE);
    xthread_spin_lock(&xthread_sched_lock);
    xthread_struct_t *cur = xthread_current;
    cur->state = state;
    xthread_schedule();
}

int xthread_unblock(xthread_struct_t *thread)
{
    if (xthread_spin_trylock(&thread->lock))
        return -1;
    if (thread->state != XTHREAD_BLOCK) {
        xthread_spin_unlock(&thread->lock);
        return -1;
    }
    if (xthread_spin_trylock(&xthread_ready_list_lock)) {
        xthread_spin_unlock(&thread->lock);
        return -1;
    }
    thread->state = XTHREAD_READY;
    xthread_spin_unlock(&thread->lock);
    /* add to head for getting more chance to sched */
    list_add(&thread->list, &xthread_ready_list_head);
    xthread_spin_unlock(&xthread_ready_list_lock);
    return 0;
}

static void xthread_environment(void)
{
    xthread_exit(xthread_current->start_routine(xthread_current->arg));
}

int xthread_create(xthread_t *tid, xthread_attr_t *attr, void * (*start_routine) (void *), void *arg)
{
    if (!start_routine) {
        return EINVAL;
    }
    /* xthread init for first call this func */
    if (!__xthread_init_done) {
        xthread_init();
    }
    /* make attr */
    xthread_attr_t default_attr;
    if (attr == NULL) {
        if (xthread_make_default_attr(&default_attr) < 0) {
            return ENOMEM;
        }
    }
    /* create thread by attr */
    xthread_struct_t *thread = malloc(sizeof(xthread_struct_t));
    if (!thread) {
        if (attr == NULL) {
            xthread_attr_destroy(&default_attr);
        }
        return ENOMEM;
    }
    memset(thread, 0, sizeof(xthread_struct_t));
    xthread_spin_init(&thread->lock);

    /* init thread struct */
    thread->state = XTHREAD_READY;
    
    thread->attr = (attr == NULL) ? default_attr : *attr;
    if (xthread_current)
        thread->parent_tid = xthread_current->tid;
    else
        thread->parent_tid = 0;
    thread->tid = xthread_alloc_tid();
    thread->start_routine = start_routine;
    thread->arg = arg;
    thread->timeslice = XTHREAD_TIMESLICE_DFL;
    thread->ticks = thread->timeslice;
    thread->exit_status = (void *)0;
    thread->flags = 0;
    xthread_timer_set(&thread->sleep_timer, 0, NULL, NULL);
    if (thread->attr.detachstate == XTHREAD_CREATE_DETACHED) {
        thread->flags |= XTHREAD_FLAG_DETACHED;
    }
    xthread_spin_lock(&xthread_ready_list_lock);
    list_add_tail(&thread->list, &xthread_ready_list_head);
    xthread_spin_unlock(&xthread_ready_list_lock);
    
    xthread_spin_lock(&xthread_global_list_lock);
    list_add_tail(&thread->global_list, &xthread_global_list_head);
    xthread_spin_unlock(&xthread_global_list_lock);
    
    xthread_spin_lock(&xthread_counts_lock);
    xthread_counts++;
    xthread_spin_unlock(&xthread_counts_lock);
    
    xthread_context_init(thread);
    makecontext(&thread->context, xthread_environment, 0);
    
    if (tid)
        *tid = thread->tid;
    return 0;
}

static int xthread_master_init()
{
    xthread_struct_t *thread = &xthread_master;
    if (xthread_make_default_attr(&thread->attr) < 0)
        return -1;
    xthread_spin_init(&thread->lock);
    xthread_spin_lock(&thread->lock);
    thread->parent_tid = 0;
    thread->tid = xthread_alloc_tid();
    thread->timeslice = 1;
    thread->ticks = thread->timeslice;
    thread->state = XTHREAD_RUNNING;    /* first thread is running */
    thread->arg = (void *) 0;
    thread->start_routine = NULL;
    thread->exit_status = (void *) 0;
    thread->flags = 0;
    xthread_timer_set(&thread->sleep_timer, 0, NULL, NULL);
    xthread_counts++;
    list_init(&thread->list);
    list_add_tail(&thread->global_list, &xthread_global_list_head);
    xthread_context_init(thread);
    xthread_spin_unlock(&thread->lock);
    
    xthread_current = thread;
    return 0;
}

static unsigned long xthread_getmstime()
{
    struct timeval tv;
    if (gettimeofday(&tv, NULL) < 0) {
        perror("xthread: gettimeofday failed!\n");
        exit(-1);
    }
    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

static void __xthread_deal_current(xthread_struct_t *cur)
{
    
    switch (cur->state)
    {
    case XTHREAD_RUNNING:
        xthread_spin_lock(&cur->lock);
        cur->ticks = cur->timeslice;
        cur->state = XTHREAD_READY;
        xthread_spin_unlock(&cur->lock);
    case XTHREAD_READY:
        xthread_spin_lock(&xthread_ready_list_lock);
        list_add_tail(&cur->list, &xthread_ready_list_head);
        xthread_spin_unlock(&xthread_ready_list_lock);
        break;
    default:
        break;
    }
    
}

static xthread_struct_t *__xthread_get_next_thread()
{
    xthread_struct_t *next = NULL;
    xthread_spin_lock(&xthread_ready_list_lock);
    next = list_first_owner_or_null(&xthread_ready_list_head, xthread_struct_t, list);
    if (next == NULL) {
        xthread_spin_unlock(&xthread_ready_list_lock);
        perror("xthread: no thread ready to sched!\n");
        panic();
    }
    list_del_init(&next->list);
    xthread_spin_unlock(&xthread_ready_list_lock);
    return next;
}

static void __xthread_set_next_thread(xthread_struct_t *next)
{
    next->state = XTHREAD_RUNNING;
    xthread_current = next;
}

static void __xthread_switch_to(xthread_struct_t *prev, xthread_struct_t *next)
{
    //XLOG("xthread: switch from %x to %x\n", prev->tid, next->tid);
    #if PRINT_SCHED == 1
    printf("xthread: switch from %x:%d to %x:%d\n", prev->tid, prev->state, next->tid, next->state);
    #endif
    if (next == prev) {
        xthread_spin_unlock(&xthread_sched_lock);
        return; // do not switch
    }
    xthread_spin_unlock(&xthread_sched_lock);
    swapcontext(&prev->context, &next->context);
}

static void  xthread_schedule()
{
    xthread_struct_t *prev = xthread_current;
    __xthread_deal_current(prev);
    xthread_struct_t *next = __xthread_get_next_thread();
    __xthread_set_next_thread(next);
    __xthread_switch_to(prev, next);
}

static int xthread_destroy(xthread_struct_t *thread)
{
    int exit_all = 0;
    /* thread list must be none */ 
    if (xthread_spin_trylock(&xthread_global_list_lock))
        return -1;
    
    if(xthread_spin_trylock(&xthread_counts_lock)) {
        xthread_spin_unlock(&xthread_global_list_lock);
        return -1;
    }
    xthread_counts--;
    xthread_spin_unlock(&xthread_counts_lock);
    
    list_del_init(&thread->global_list);
    xthread_spin_unlock(&xthread_global_list_lock);
    
    xthread_attr_destroy(&thread->attr);
    xthread_free_tid(thread->tid);
    if (thread != &xthread_master)
        free(thread);
    return 0;
}

void xthread_yield()
{
    if (!__xthread_init_done)
        return;
    XTHREAD_CHECK_CANCELATION_POTINT(xthread_current);
    xthread_spin_lock(&xthread_sched_lock);
    xthread_current->state = XTHREAD_READY;
    xthread_schedule();
}

static void xthread_sleep_timer_handler(void *arg)
{
    xthread_struct_t *thread = (xthread_struct_t *)arg;
    if (xthread_unblock(thread) < 0)
        __xtimer_handle_failed = -1;
}

int xthread_sleep(int seconds)
{
    if (!__xthread_init_done)
        return -1;
    if (!seconds)
        return -1;
    /* set sleep timer and block */
    xthread_struct_t *cur = xthread_current;
    XTHREAD_CHECK_CANCELATION_POTINT(cur);
    xthread_timer_t *timer = &cur->sleep_timer;
    xthread_timer_modify(timer, seconds * 1000);
    xthread_timer_setarg(timer, cur);
    xthread_timer_sethandler(timer, xthread_sleep_timer_handler);
    xthread_timer_add(timer);
    xthread_block(XTHREAD_BLOCK);
    /* calc the time left */
    int dt = cur->sleep_timer.timeout - __xthread_alarm_ticks;
    cur->sleep_timer.timeout  = 0;
    if (dt > 0)
        return dt / 1000;
    return 0;
}

void xthread_usleep(int usec)
{
    if (!__xthread_init_done)
        return;
    xthread_struct_t *cur = xthread_current;
    XTHREAD_CHECK_CANCELATION_POTINT(cur);
    int msec = usec / 1000;

    if (msec <= 2) { /* use delay */
        int i, j, k;
        for (i = 0; i < msec + 1; i++) {
            for (j = 0; j < 100; j++) {
                for (k = 0; k < 10000; k++) {}    
            }
        }
        return;
    }
    unsigned long wakeuptime = xthread_getmstime() + msec;
    while (xthread_getmstime() < wakeuptime) {
        xthread_yield();
    }
}

xthread_t xthread_self(void)
{
    if (!__xthread_init_done)
        return 0;
    if (!xthread_current) {
        printf("xthread: current thread is null!\n");
        panic();
    }
    return xthread_current->tid;
}

int xthread_equal(xthread_t thread1, xthread_t thread2)
{
    return thread1 == thread2;
}

int xthread_detach(xthread_t tid)
{
    if (!__xthread_init_done)
        return -1;
    xthread_struct_t *target_thread = xthread_find_by_tid(tid);
    if (!target_thread)
        return -1;
    xthread_struct_t *parent_thread = xthread_find_by_tid(target_thread->parent_tid);
    if (!parent_thread)
        return -1;
    xthread_spin_lock(&target_thread->lock);
    
    target_thread->flags |= XTHREAD_FLAG_DETACHED;
    /* found tid's parent thread, clear for the parent's joining flags */
    if (target_thread->flags & XTHREAD_FLAG_JOINEDBY) {
        if (parent_thread && (parent_thread->flags & XTHREAD_FLAG_JOINING)) {
            xthread_spin_lock(&parent_thread->lock);
    
            parent_thread->flags &= ~XTHREAD_FLAG_JOINING;
            xthread_spin_unlock(&parent_thread->lock);
    
            /* adopt to sys thread */
            target_thread->parent_tid = xthread_sys_tid;
        }
    }
    xthread_spin_unlock(&target_thread->lock);
    return 0;
}

int xthread_join(xthread_t tid, void **thread_return)
{
    if (!__xthread_init_done)
        return -1;
    XTHREAD_CHECK_CANCELATION_POTINT(xthread_current);
    xthread_struct_t *target_thread = xthread_find_by_tid(tid);
    if (!target_thread)
        return -1;
    /* detached thread can't join */
    if (target_thread->flags & XTHREAD_FLAG_DETACHED)
        return -1;
    /* only could be joined by one thread */
    if (target_thread->flags & XTHREAD_FLAG_JOINEDBY)
        return -1;
    if (target_thread->state == XTHREAD_ZOMBIE) {
        printf("child thread %d zombie!\n", target_thread->tid);
        return -1;    
    }
    xthread_spin_lock(&target_thread->lock);
    /* target was joined by current thread */
    target_thread->flags |= XTHREAD_FLAG_JOINEDBY;
    /* join to current thread */
    xthread_struct_t *cur = xthread_current;
    target_thread->parent_tid = cur->tid;
    xthread_spin_unlock(&target_thread->lock);
    
    xthread_spin_lock(&cur->lock);
    cur->flags |= XTHREAD_FLAG_JOINING;
    xthread_spin_unlock(&cur->lock);
    while (1) {
        if (target_thread->state == XTHREAD_ZOMBIE)
            break;
        /* if current thread is not joning while joining, we need end of joining it. */
        if (!(cur->flags & XTHREAD_FLAG_JOINING)) {
            break;
        }
    }
    if (thread_return) {
        *thread_return = target_thread->exit_status;
    }
    XPRINT("xthread: parent %x join %x\n", cur->tid, target_thread->tid);
    /* destroy thread by current thread */
    if (target_thread->parent_tid == cur->tid && target_thread->state == XTHREAD_ZOMBIE) {
        XPRINT("[ok]\n");
        /* adopt to sys thread */
        target_thread->parent_tid = xthread_sys_tid;
    } else {    /* parent changed */
        XPRINT("[failed]\n");
        return -1;
    }
    return 0;
}

int xthread_cancel(xthread_t tid)
{
    if (!__xthread_init_done)
        return -1;
    xthread_struct_t *thread = xthread_find_by_tid(tid);
    if (!thread)
        return EPERM;
    XPRINT("xthread: cancel %lx\n", thread->tid);
    xthread_spin_lock(&thread->lock);
    thread->flags |= XTHREAD_FLAG_CANCELED;
    xthread_spin_unlock(&thread->lock);
    if (thread->flags & XTHREAD_FLAG_CANCEL_ASYCHRONOUS) {
        /* need cancel now */
        xthread_exit_one(thread, (void *) XTHREAD_FLAG_CANCEL_ASYCHRONOUS);
    }
    XTHREAD_CHECK_CANCELATION_POTINT(xthread_current);
    return 0;
}

int xthread_setcancelstate(int state, int *oldstate)
{
    if (!__xthread_init_done)
        return -1;
    xthread_struct_t *cur = xthread_current;
    xthread_spin_lock(&cur->lock);
    if (oldstate != NULL) {
        if (cur->flags & XTHREAD_FLAG_CANCEL_DISABLE) {
            *oldstate = XTHREAD_CANCEL_DISABLE;
        } else {
            *oldstate = XTHREAD_CANCEL_ENABLE;
        }
    }
    if (state == XTHREAD_CANCEL_DISABLE) {
        cur->flags |= XTHREAD_FLAG_CANCEL_DISABLE;
    } else if (state == XTHREAD_CANCEL_ENABLE) {
        cur->flags &= ~XTHREAD_FLAG_CANCEL_DISABLE;
    } else {
        return -1;
    }
    xthread_spin_unlock(&cur->lock);
    return 0;
}

int xthread_setcanceltype(int type, int *oldtype)
{
    if (!__xthread_init_done)
        return -1;
    xthread_struct_t *cur = xthread_current;
    xthread_spin_lock(&cur->lock);
    if (oldtype != NULL) {
        if (cur->flags & XTHREAD_FLAG_CANCEL_ASYCHRONOUS) {
            *oldtype = XTHREAD_CANCEL_ASYCHRONOUS;
        } else {
            *oldtype = XTHREAD_CANCEL_DEFFERED;
        }
    }
    if (type == XTHREAD_CANCEL_ASYCHRONOUS) {
        cur->flags |= XTHREAD_FLAG_CANCEL_ASYCHRONOUS;
    } else if (type == XTHREAD_CANCEL_DEFFERED) {
        cur->flags &= ~XTHREAD_FLAG_CANCEL_ASYCHRONOUS;
    } else {
        return -1;
    }
    xthread_spin_unlock(&cur->lock);
    return 0;
}

void xthread_testcancel(void)
{
    if (!__xthread_init_done)
        return;
    XTHREAD_CHECK_CANCELATION_POTINT(xthread_current);
}

/* alarm must be trylock ready list, it can't interrupt other thread */
static void xthread_alarm_handler(int signo)
{ 
    __xthread_alarm_ticks += XTHREAD_ALARM_MS;
    xthread_timer_update();
    xthread_struct_t *cur = xthread_current;
    if (!cur) {
        return;
    }
    /* can't intterupt ready list */
    if (xthread_spin_trylock(&xthread_ready_list_lock)) {
        return;
    }
    //printf("alarm ticks: %d\n", __xthread_alarm_ticks);
    XLOG("alarm thread: tid %x, ticks %d\n", cur->tid, cur->ticks);
    if (xthread_spin_trylock(&cur->lock)) {
        xthread_spin_unlock(&xthread_ready_list_lock);
        return;
    }
    cur->ticks--;
    if (cur->ticks > 0) {
        xthread_spin_unlock(&cur->lock);
        xthread_spin_unlock(&xthread_ready_list_lock);
        return;
    }
    cur->ticks = 0;
    xthread_spin_unlock(&cur->lock);
    xthread_spin_unlock(&xthread_ready_list_lock);
    if (xthread_spin_trylock(&xthread_sched_lock)) {
        return;   
    }
    xthread_schedule();
}

int xthread_enable_interrupt()
{
    if (xthread_alarm_installed)
        return -1;
    struct itimerval value;
    value.it_value.tv_sec = 0;
    value.it_value.tv_usec = 1000;
    value.it_interval.tv_sec = 0;
    value.it_interval.tv_usec = 1000 * XTHREAD_ALARM_MS; // vulue is 10 ms
    if (setitimer(ITIMER_REAL, &value, NULL) < 0) {
        perror("xthread: install alarm failed!\n");
        return -1;
    }
    signal(SIGALRM, xthread_alarm_handler);
    xthread_alarm_installed = 1;
    return 0;
}

int xthread_disable_interrupt()
{
    if (!xthread_alarm_installed)
        return -1;
    struct itimerval value;
    value.it_value.tv_sec = 0;
    value.it_value.tv_usec = 0;
    value.it_interval.tv_sec = 0;
    value.it_interval.tv_usec = 0;
    if (setitimer(ITIMER_REAL, &value, NULL) < 0) {
        perror("xthread: uninstall alarm failed!\n");
        return -1;
    }
    signal(SIGALRM, SIG_DFL);
    xthread_alarm_installed = 0;
    return 0;
}

static void xthread_disablealarm()
{
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGALRM);
    if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
        perror("xthread: disable arlarm failed, because of sigprocmask!\n");
        panic();
    }
    signal(SIGALRM, SIG_IGN);
}

static void xthread_enablealarm()
{
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGALRM);
    if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0)
    {
        perror("xthread: enable arlarm failed, because of sigprocmask!\n");
        panic();
    }
    if (xthread_alarm_installed)
        signal(SIGALRM, xthread_alarm_handler);
    else
        signal(SIGALRM, SIG_DFL);
}

static void xthread_exit_all()
{
    if (!__xthread_init_done)
        return;
    xthread_disablealarm();
    xthread_disable_interrupt();
    XPRINT("xthread: exit all thread done.\n");
}

static void *xthread_sys_entry(void *arg)
{
    xthread_struct_t *thread, *parent_thread;
    xthread_t tid, parent_tid;
    while (1) {
        if (xthread_spin_trylock(&xthread_zombie_list_lock)) {
            xthread_yield();
            continue;
        }
        /* each time deal one zombie thread */
        thread = list_first_owner_or_null(&xthread_zombie_list_head, xthread_struct_t, list);
        if (thread && thread->state == XTHREAD_ZOMBIE) {
            tid = thread->tid;
            list_del_init(&thread->list); /* del from zombie list */
            if (thread->parent_tid == xthread_sys_tid) {
                if (xthread_destroy(thread) < 0) {
                    list_add_tail(&thread->list, &xthread_zombie_list_head); 
                    XPRINT("xthread: sys release zombie %lx failed\n", tid);
                } else {
                    XPRINT("xthread: sys release zombie %lx ok\n", tid);
                }
            } else {
                list_add_tail(&thread->list, &xthread_zombie_list_head); 
            }
        }
        xthread_spin_unlock(&xthread_zombie_list_lock);
        
        if(xthread_spin_trylock(&xthread_counts_lock)) {
            xthread_yield();
            continue;
        }
        if (xthread_counts <= 1)
            exit(0);
        xthread_spin_unlock(&xthread_counts_lock);
        
        xthread_yield();
    }
    return NULL;
}

/* get the best thread count in current state. */
unsigned long xthread_best_count()
{
    struct sysinfo si;
    sysinfo(&si);
    int tsize = sizeof(xthread_struct_t) + XTHREAD_STACKSIZE_DEL;
    unsigned long tcount = si.freeram / tsize;
    return tcount;
}

static int xthread_init()
{
    if (__xthread_init_done)
        return -1;
    xthread_spin_init(&xthread_ready_list_lock);
    xthread_spin_init(&xthread_global_list_lock);
    xthread_spin_init(&xthread_zombie_list_lock);
    xthread_spin_init(&xthread_sched_lock);
    xthread_spin_init(&xthread_counts_lock);
    
    if (xthread_master_init() < 0) {
        perror("xthread: init failed because master thread init failed!\n");
        return -1;
    }
    if (xthread_enable_interrupt() < 0) {
        perror("xthread: init failed because enable interrupt failed!\n");
        return -1;
    }
    xthread_enablealarm();
    atexit(xthread_exit_all);
    xthread_timer_init();
    __xthread_init_done = 1;
    /* create a sys thread to deal zombie thread */
    if (xthread_create(&xthread_sys_tid, NULL, xthread_sys_entry, NULL) < 0) {
        perror("xthread: create sys thread failed!\n");
        return -1;
    }
    return 0;
}